#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "cJSON.h"
#define N 256
char ver[256] = "v1.0.1";
char rec_ver[256] = "";

// 添加解压函数
void extract_zip(const char *filename)
{
    char command[512];
    snprintf(command, sizeof(command), "unzip -o %s -d /home/hq/25021/gym/4-bigproject/update", filename);
    int ret = system(command);
    if (ret != 0)
    {
        printf("解压失败: %s\n", filename);
        return;
    }

    // 这里可以添加文件替换逻辑
    // 例如: system("cp /tmp/update/* /usr/local/bin/");
    printf("文件解压并替换成功\n");
}

int main(int argc, char const *argv[])
{
    int broadfd;

    // 创建一个 UDP socket
    broadfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (broadfd < 0)
    {
        perror("sock err");
        return -1;
    }

    // 绑定 UDP 套接字 (0.0.0.0:9876)
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(9876); // UDP 端口 9876
    addr.sin_addr.s_addr = INADDR_ANY;

    int addrlen = sizeof(addr);

    if (bind(broadfd, (struct sockaddr *)&addr, addrlen) < 0)
    {
        perror("bind err");
        return -1;
    }

    ssize_t len;
    char buf[N] = {0};
    struct sockaddr_in cliaddr;

    // 接收 "hello world" 广播
    bzero(buf, N);
    len = recvfrom(broadfd, buf, N, 0, (struct sockaddr *)&cliaddr, &addrlen);
    if (len < 0)
    {
        perror("recvfrom failed");
        return -1;
    }

    // 检查是否是 "hello world"
    if (strcmp(buf, "hello world") != 0)
    {
        printf("Received invalid message: %s\n", buf);
        return -1;
    }
    printf("Received: %s\n", buf);

    // json反序列化
    char buffer[2048] = "";
    FILE *fp = fopen("./node.json", "r");
    if (fp == NULL)
    {
        perror("fopen err");
        return -1;
    }
    fread(buffer, 2048, 1, fp);

    cJSON *root = cJSON_Parse(buffer);
    cJSON *item = cJSON_GetObjectItem(root, "mqtt_server");
    cJSON *port = cJSON_GetObjectItem(item, "port");
    cJSON *addrm = cJSON_GetObjectItem(item, "addr");

    // 回复 "yes" 到发送方（明确指定端口 9876）
    cliaddr.sin_port = htons(9876); // 强制回复到 9876 端口
    cJSON *json = cJSON_CreateObject();
    cJSON_AddItemToObject(json, "type", cJSON_CreateNumber(0));
    cJSON *data = cJSON_CreateObject();
    cJSON_AddItemToObject(data, "mqtt_address", cJSON_CreateString(addrm->valuestring));
    cJSON_AddItemToObject(data, "mqtt_port", cJSON_CreateNumber(port->valueint));
    cJSON_AddItemToObject(data, "tcp_address", cJSON_CreateString(addrm->valuestring));
    cJSON_AddItemToObject(data, "tcp_port", cJSON_CreateNumber(9877));
    cJSON_AddItemToObject(json, "data", data);
    char *ptr = cJSON_PrintUnformatted(json);
    int bytes_sent = sendto(broadfd, ptr, strlen(ptr), 0, (struct sockaddr *)&cliaddr, addrlen);
    free(ptr);
    if (bytes_sent < 0)
    {
        perror("sendto failed");
        return -1;
    }
    printf("Reply sent to %s:%d\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));

    // 创建 TCP socket（使用不同端口 9877）
    int tcpfd = socket(AF_INET, SOCK_STREAM, 0);
    if (tcpfd < 0)
    {
        perror("TCP sock err");
        return -1;
    }

    struct sockaddr_in tcp_addr, caddr;
    tcp_addr.sin_family = AF_INET;
    tcp_addr.sin_port = htons(9877);
    tcp_addr.sin_addr.s_addr = inet_addr("192.168.31.170");
    addrlen = sizeof(tcp_addr);

    if (bind(tcpfd, (struct sockaddr *)&tcp_addr, addrlen) < 0)
    {
        perror("TCP bind err");
        return -1;
    }

    // 监听 TCP
    if (listen(tcpfd, 5) < 0)
    {
        perror("listen err");
        return -1;
    }

    printf("TCP server waiting on port 9877...\n");
    int clifd = accept(tcpfd, (struct sockaddr *)&caddr, &addrlen);
    if (clifd < 0)
    {
        perror("accept err");
        return -1;
    }
    printf("client ip : %s  port:%d\n", inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
    printf("New TCP connection accepted\n");
    char buf1[1024] = {};
    while (1)
    {
        int ret = recv(clifd, buf1, sizeof(buf1) - 1, 0);
        if (ret < 0)
        {
            perror("recv err");
            return -1;
        }
        else if (ret == 0)
        {
            printf("client exit\n");
            break;
        }
        buf1[ret] = '\0';

        // 检查是否是文件头信息 (包含|分隔符)
        char *header_sep = strchr(buf1, '|');
        if (header_sep != NULL)
        {
            *header_sep = '\0';
            char *filename = buf1;
            long filesize = atol(header_sep + 1);

            printf("接收文件: %s, 大小: %ld\n", filename, filesize);

            // 接收文件内容
            FILE *file = fopen(filename, "wb");
            if (!file)
            {
                perror("fopen error");
                send(clifd, "error", 6, 0);
                return -1;
            }

            long total_received = 0;
            char file_buffer[4096];

            while (total_received < filesize)
            {
                ssize_t bytes = recv(clifd, file_buffer, sizeof(file_buffer), 0);
                if (bytes <= 0)
                    break;
                fwrite(file_buffer, 1, bytes, file);
                total_received += bytes;
                printf("已接收: %ld/%ld bytes\n", total_received, filesize);
            }

            fclose(file);

            // 校验文件大小
            struct stat st;
            stat(filename, &st);
            if (st.st_size != filesize)
            {
                printf("文件大小不匹配: 实际 %ld, 预期 %ld\n", st.st_size, filesize);

                // 发送传输失败响应
                cJSON *root = cJSON_CreateObject();
                cJSON_AddNumberToObject(root, "type", 2);
                cJSON *data = cJSON_CreateObject();
                cJSON_AddStringToObject(data, "trans_success", "false");
                cJSON_AddItemToObject(root, "data", data);

                char *json_str = cJSON_PrintUnformatted(root);
                send(clifd, json_str, strlen(json_str), 0);

                cJSON_Delete(root);
                free(json_str);
                continue;
            }

            printf("文件接收完成: %s\n", filename);

            // 发送传输成功响应
            cJSON *root = cJSON_CreateObject();
            cJSON_AddNumberToObject(root, "type", 2);
            cJSON *data = cJSON_CreateObject();
            cJSON_AddStringToObject(data, "trans_success", "true");
            cJSON_AddItemToObject(root, "data", data);

            char *json_str = cJSON_PrintUnformatted(root);
            send(clifd, json_str, strlen(json_str), 0);

            cJSON_Delete(root);
            free(json_str);

            // 解压并升级
            extract_zip(filename);

            // 发送升级成功响应
            root = cJSON_CreateObject();
            cJSON_AddNumberToObject(root, "type", 3);
            data = cJSON_CreateObject();
            cJSON_AddStringToObject(data, "update_success", "true");
            cJSON_AddItemToObject(root, "data", data);

            json_str = cJSON_PrintUnformatted(root);
            send(clifd, json_str, strlen(json_str), 0);

            cJSON_Delete(root);
            free(json_str);

            continue;
        }

        cJSON *root = cJSON_Parse(buf1);
        if (NULL == root)
        {
            printf("parse err\n");
            return -1;
        }

        // 获取root节点上名字叫type的子节点
        cJSON *item = cJSON_GetObjectItem(root, "type");
        printf("type = %d\n", item->valueint);

        // 如果是升级问询(type=1)
        if (item->valueint == 1)
        {
            // 获取data对象
            cJSON *data = cJSON_GetObjectItem(root, "data");
            if (data && data->type == cJSON_Object)
            {
                cJSON *ver = cJSON_GetObjectItem(data, "ver");
                strncpy(rec_ver, ver->valuestring, sizeof(rec_ver) - 1);
                rec_ver[sizeof(rec_ver) - 1] = '\0';

                printf("Received version: %s\n", rec_ver);

                // 创建响应JSON
                cJSON *response = cJSON_CreateObject();
                cJSON_AddNumberToObject(response, "type", 1);

                cJSON *response_data = cJSON_CreateObject();
                // 比较版本号，如果接收到的版本大于"v1.0.1"则需要升级
                if (strcmp(rec_ver, "v1.0.1") > 0)
                {
                    cJSON_AddTrueToObject(response_data, "update");
                    printf("Version %s is newer, need update\n", rec_ver);
                }
                else
                {
                    cJSON_AddFalseToObject(response_data, "update");
                    printf("Version %s is same or older, no need update\n", rec_ver);
                }
                cJSON_AddItemToObject(response, "data", response_data);

                // 发送响应
                char *response_str = cJSON_PrintUnformatted(response);
                send(clifd, response_str, strlen(response_str), 0);
                printf("Sent response: %s\n", response_str);

                // 释放内存
                cJSON_Delete(response);
                free(response_str);
            }
        }

        // 释放内存
        cJSON_Delete(root);
    }
    close(clifd);
    close(tcpfd);
    close(broadfd);

    return 0;
}